﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;

namespace LostLib.Programs
{
	partial class AssemblyInfo
	{
		/// <summary>
		/// Gets installed version of this Assembly.
		/// </summary>
		/// <returns>Installed version or null if nothing is installed.</returns>
		public AssemblyVersion InstalledVersion
		{
			get
			{
				var gac = new HashSet<string>(GlobalAssemblyCache.GetAssemblies(true).Select(assembly => assembly.FullName) );

				foreach (var version in AssemblyVersions.OrderByDescending(ver => ver.Version))
					if (gac.Contains(version.FullName.FullName)) return version;

				return null;
			}
		}

		public AssemblyState State
		{
			get
			{
				if (InstalledVersion == null) return AssemblyState.NotInstalled;
				if (LatestSuitable == null) return AssemblyState.Latest;
				if (InstalledVersion.Version >= LatestSuitable.Version) return AssemblyState.Latest;
				return AssemblyState.Installed;
			}
		}

		/// <summary>
		/// Gets latest suitable version of this Assembly.
		/// </summary>
		/// <returns>Latest suitable verions or null if nothing is installed.</returns>
		public AssemblyVersion LatestSuitable
		{
			get
			{
				return (from version in AssemblyVersions
						where version.Suitable
						orderby version.Version descending
						select version).FirstOrDefault();
			}
		}

		public bool IsInstalled
		{
			get
			{
				return InstalledVersion != null;
			}
			set
			{
				if (IsInstalled == value) return;

				SendPropertyChanging();
				if (value)
				{
					
					if (LatestSuitable == null)
						throw new InvalidOperationException("There's no suitable versions to install");

					AssemblyManager.Install(LatestSuitable);
				} else
				{
					AssemblyManager.Remove(InstalledVersion);
				}
				SendPropertyChanged("IsInstalled");
				SendPropertyChanged("IsLatest");
			}
		}

		public bool IsNewerVersionAvailable
		{
			get
			{
				if (LatestSuitable == null) return false;
				if (InstalledVersion == null) return true;
				return LatestSuitable.Version > InstalledVersion.Version;
			}
		}

		/// <summary>
		/// Converts Assembly to string.
		/// </summary>
		/// <returns>String representation of Assembly.</returns>
		public override string ToString()
		{
			return AssemblyName;
		}
		
		internal static AssemblyInfo Parse(XmlNode AssemblyNode)
		{
			var Assembly = new AssemblyInfo() {
				AssemblyName = AssemblyNode.Attributes["name"].Value,
				Description = AssemblyNode.Attributes["desc"].Value,
			};

			return Assembly;
		}
	}

	[Serializable]
	public enum AssemblyState
	{
		NotInstalled,
		Installed,
		Latest,
	}
}
